home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / lysrc.zip / YACCLOOK.PAS < prev    next >
Pascal/Delphi Source File  |  1993-01-24  |  15KB  |  381 lines

  1.  
  2. unit YaccLookaheads;
  3.  
  4. (* 3-1-91 AG *)
  5.  
  6. (* Copyright (c) 1990,91 by Albert Graef, Schillerstr. 18,
  7.    6509 Schornsheim/Germany
  8.    All rights reserved *)
  9.  
  10. interface
  11.  
  12. (* Yacc lookahead computation. This implementation is based on the
  13.    lookahead set algorithm described in Aho/Sethi/Ullman, 1986,
  14.    Section 4.7. *)
  15.  
  16. procedure lookaheads;
  17.   (* computes the LALR lookahead sets and enters corresponding reductions
  18.      into the redn table (sorted w.r.t. rule numbers) *)
  19.  
  20. implementation
  21.  
  22. uses YaccBase, YaccTables;
  23.  
  24. (* This implementation is based on algorithms 4.12 and 4.13 in Aho/Sethi/
  25.    Ullman 1986 (with some optimizations added), which avoid the need to
  26.    construct the full LR(1) set, and are able to compute lookaheads from
  27.    LR(0) kernel items only.
  28.  
  29.    We start off with the LR(0) state set together with corresponding (shift
  30.    and goto) transitions already computed. We compute the LALR(1) lookahead
  31.    sets for kernel items and also record all corresponding reduce actions
  32.    in the reduction table (where we also have to consider nonkernel items
  33.    with empty right-hand side; these items also call for a reduction, but
  34.    never appear in the kernel item table).
  35.  
  36.    This implementation uses some simple optimizations to speed up the
  37.    algorithm. The lookahead sets are represented by (IntSet) pointers.
  38.    Lookahead sets are associated with each kernel item in the item table,
  39.    and with each reduction in the reduction table. A kernel item
  40.    calling for a reduction shares its lookahead set pointer with the
  41.    corresponding entry in the reduction table. The lookahead set for
  42.    a nonkernel reduction item (item with empty right-hand side) only
  43.    appears in the reduction table.
  44.  
  45.    The algorithm consists of two phases:
  46.  
  47.    1. Initialization:
  48.  
  49.       The initialization phase consists of a single traversal of the LR(0)
  50.       set, where we compute lookahead sets generated spontaneously (lookaheads
  51.       which are passed on from nonkernel items to the corresponding items in
  52.       successor states), initialize lookahead sets and enter them into the
  53.       lookahead and reduction table. Furthermore, during the initialization
  54.       phase we also initialize the links for the propagation of lookaheads
  55.       in the second phase.
  56.  
  57.       To determine lookaheads and propagation links, we compute the look-
  58.       aheads for the closures of single LR(0) sets "in the small", according
  59.       to the method in Aho/Sethi/Ullman 1986 (with some modifications),
  60.       where we associate with each kernel item i a corresponding endmarker
  61.       symbol #i as its lookahead symbol.
  62.  
  63.       The initialization phase proceeds as follows:
  64.  
  65.       1) Initialize all nonkernel item lookahead sets to empty.
  66.  
  67.       Now we pass over each state s in the LR0 set, repeating steps 2) thru
  68.       5) specified below:
  69.  
  70.       2) Compute the closure closure(K(s)) of the states's kernel set K(s).
  71.  
  72.       3) Compute the lookahead sets for closure(K(s)) (described in detail
  73.          below) where each kernel item i is associated with a special
  74.          endmarker symbol #i as lookahead.
  75.  
  76.       Now the lookahead symbols, reductions and propagation links are entered
  77.       into the corresponding tables as follows:
  78.  
  79.       4) Process kernel items: Add a propagation link from the kernel item
  80.          to the lookahead set of the linked item in the corresponding
  81.          successor state (as specified by the next field). If there is no
  82.          successor item (kernel item calling for a reduction), add a
  83.          corresponding entry into the reduction table instead.
  84.  
  85.       5) Process nonkernel items: find the corresponding kernel item in the
  86.          successor state which is generated spontaneously from the nonkernel
  87.          item. Add the spontaneous lookahead symbols (except endmarker
  88.          symbols) of the nonkernel item determined in step 3) to the kernel
  89.          item. If the nonkernel item has an empty right-hand side (nonkernel
  90.          item calling for a reduction), add a corresponding entry into the
  91.          reduction table instead. Furthermore, for each endmarker symbol
  92.          #i in the spontaneous lookahead set of the nonkernel item, add
  93.          a corresponding propagation link from the ith kernel item to the
  94.          lookahead set of the spontaneous kernel item.
  95.  
  96.       To compute the spontaneous lookaheads (step 3)), we proceed as follows:
  97.  
  98.       3a) First compute the first sets of tail strings of all items in
  99.           closure(K(s)). The "tail string" of an item [ X -> v.Yw ], where
  100.           Y is a nonterminal, is the symbol sequence w, whose first set
  101.           induces corresponding spontaneous lookaheads in the nonkernel
  102.           items of the state with left-hand side Y; note that the first
  103.           sets of "tail strings" in items [ X -> v.yw ], where y is a
  104.           *terminal* symbol, are not required and hence it is not
  105.           necessary to compute them. We also record for each item whether
  106.           its tail string is "nullable", i.e., may be derived to the empty
  107.           string. In this case, the item also passes on its own lookaheads,
  108.           in addition to the first symbols of its tail string. First sets
  109.           and nullable flags are computed using the information in YaccTable's
  110.           first and nullable tables.
  111.  
  112.       3b) Now follows an initialization part in which each item [ X -> v.Yw ]
  113.           passes on the first symbols of its tail string to the lookahead
  114.           sets of each corresponding nonkernel item [ Y -> .u ].
  115.  
  116.       3c) Finally, we repeatedly pass over the item set, passing on
  117.           lookaheads from items with nullable tail strings. Each item
  118.           [ X -> v.Yw ] with nullable w propagates its own lookaheads to
  119.           all corresponding nonkernel items [ Y -> .u]. Step 3c) terminates
  120.           as soon as no lookahead sets have been modified during the previous
  121.           pass.
  122.  
  123.    2. Propagation:
  124.  
  125.       The second phase of the lookahead computation algorithm now is quite
  126.       simple. We repeatedly pass over all kernel items, propagating lookaheads
  127.       according to the propagation links determined in the initialization
  128.       phase. The algorithm terminates as soon as no lookahead sets have been
  129.       modified during the previous pass. *)
  130.  
  131. (* Data structures used in lookahead computation: *)
  132.  
  133. type
  134.  
  135. SymSetArray = array [1..max_set_items] of IntSet;
  136. BoolArray   = array [1..max_set_items] of Boolean;
  137.  
  138. var
  139.  
  140. item_set       : ItemSet;
  141. lookahead_set  : SymSetArray;
  142. n_kernel_items : Integer;
  143.  
  144. procedure spontaneous_lookaheads;
  145.  
  146.   (* compute spontaneous lookaheads for item_set; negative symbols are
  147.      used for endmarkers (-i denotes endmarker #i) *)
  148.  
  149.   var count, last_count, i : Integer;
  150.       first_syms : SymSetArray;
  151.       nullable : BoolArray;
  152.  
  153.   function sym_count ( n : Integer ) : Integer;
  154.     (* count lookahead symbols *)
  155.     var count, i : Integer;
  156.     begin
  157.       count := 0;
  158.       for i := 1 to n do
  159.         inc(count, size(lookahead_set[i]));
  160.       sym_count := count;
  161.     end(*sym_count*);
  162.  
  163.   procedure compute_first_syms ( i : Integer );
  164.     (* compute first set and nullable flag for tail string of item
  165.        number i *)
  166.     var j : Integer;
  167.     begin
  168.       empty(first_syms[i]); nullable[i] := true;
  169.       with item_set, item[i], rule_table^[rule_no]^ do
  170.         if (pos_no<=rhs_len) and (rhs_sym[pos_no]<0) then
  171.           begin
  172.             j := pos_no+1;
  173.             while (j<=rhs_len) and nullable[i] do
  174.               begin
  175.                 if rhs_sym[j]<0 then
  176.                   begin
  177.                     setunion(first_syms[i], first_set_table^[-rhs_sym[j]]^);
  178.                     nullable[i] := YaccTables.nullable^[-rhs_sym[j]];
  179.                   end
  180.                 else
  181.                   begin
  182.                     include(first_syms[i], rhs_sym[j]);
  183.                     nullable[i] := false;
  184.                   end;
  185.                 inc(j);
  186.               end;
  187.           end;
  188.     end(*compute_first_syms*);
  189.  
  190.   procedure init_lookaheads ( i : Integer );
  191.     (* compute initial lookaheads induced by first sets of tail string
  192.        of item i *)
  193.     var sym, j : Integer;
  194.     begin
  195.       with item_set, item[i], rule_table^[rule_no]^ do
  196.         if (pos_no<=rhs_len) and (rhs_sym[pos_no]<0) then
  197.           begin
  198.             sym := rhs_sym[pos_no];
  199.             for j := n_kernel_items+1 to n_items do
  200.               with item[j], rule_table^[rule_no]^ do
  201.                 if lhs_sym=sym then
  202.                   setunion(lookahead_set[j], first_syms[i]);
  203.           end
  204.     end(*initial_lookaheads*);
  205.  
  206.   procedure propagate ( i : Integer );
  207.     (* propagate lookahead symbols of item i *)
  208.     var sym, j : Integer;
  209.     begin
  210.       with item_set, item[i], rule_table^[rule_no]^ do
  211.         if (pos_no<=rhs_len) and (rhs_sym[pos_no]<0) and nullable[i] then
  212.           begin
  213.             sym := rhs_sym[pos_no];
  214.             for j := n_kernel_items+1 to n_items do
  215.               with item[j], rule_table^[rule_no]^ do
  216.                 if lhs_sym=sym then
  217.                   setunion(lookahead_set[j], lookahead_set[i]);
  218.           end
  219.     end(*propagate*);
  220.  
  221.   begin(*spontaneous_lookaheads*)
  222.     with item_set do
  223.       begin
  224.         (* initialize kernel lookahead sets: *)
  225.         for i := 1 to n_kernel_items do singleton(lookahead_set[i], -i);
  226.         (* compute first sets and nullable flags: *)
  227.         for i := 1 to n_items do compute_first_syms(i);
  228.         (* initialize nonkernel lookahead sets: *)
  229.         for i := n_kernel_items+1 to n_items do empty(lookahead_set[i]);
  230.         for i := 1 to n_items do init_lookaheads(i);
  231.         (* repeated passes until no more lookaheads have been added
  232.            during the previous pass: *)
  233.         count := sym_count(n_items);
  234.         repeat
  235.           last_count := count;
  236.           for i := 1 to n_items do
  237.             propagate(i);
  238.           count := sym_count(n_items);
  239.         until last_count=count;
  240.       end;
  241.   end(*spontaneous_lookaheads*);
  242.  
  243. {$F+}
  244. function redns_less ( i, j : Integer ) : Boolean;
  245. {$F-}
  246.   begin
  247.     redns_less := redn_table^[i].rule_no<redn_table^[j].rule_no
  248.   end(*redns_less*);
  249.  
  250. {$F+}
  251. procedure redns_swap ( i, j : Integer );
  252. {$F-}
  253.   var x : RednRec;
  254.   begin
  255.     x := redn_table^[i];
  256.     redn_table^[i] := redn_table^[j];
  257.     redn_table^[j] := x;
  258.   end(*redns_swap*);
  259.  
  260. procedure sort_redns;
  261.   (* sort reduction entries in act_state w.r.t. rule numbers *)
  262.   begin
  263.     with state_table^[act_state] do
  264.       quicksort(redns_lo, redns_hi, redns_less, redns_swap);
  265.   end(*sort_redns*);
  266.  
  267. procedure initialize;
  268.  
  269.   (* initialization phase of lookahead computation algorithm *)
  270.  
  271.   procedure add_prop ( i : Integer; symset : IntSetPtr );
  272.     (* add a propagation link to kernel item i *)
  273.     var prop : PropList;
  274.     begin
  275.       new(prop);
  276.       prop^.symset := symset;
  277.       prop^.next := prop_table^[i];
  278.       prop_table^[i] := prop;
  279.     end(*add_prop*);
  280.  
  281.   var i, j, k : Integer;
  282.       lookaheads : IntSetPtr;
  283.  
  284.   begin
  285.     (* initialize lookahead sets and propagation links: *)
  286.     for i := 1 to n_items do lookahead_table^[i] := newEmptyIntSet;
  287.     for i := 1 to n_items do prop_table^[i] := nil;
  288.     act_state := 0;
  289.     repeat
  290.       with state_table^[act_state], item_set do
  291.         begin
  292.           start_redns;
  293.           get_item_set(act_state, item_set);
  294.           n_kernel_items := n_items;
  295.           (* compute LR(0) closure: *)
  296.           closure(item_set);
  297.           (* compute spontaneous lookaheads: *)
  298.           spontaneous_lookaheads;
  299.           (* process kernel items: *)
  300.           for i := 1 to n_kernel_items do with item[i] do
  301.             if next>0 then
  302.               (* add propagation link: *)
  303.               add_prop(item_lo+i-1, lookahead_table^[next])
  304.             else
  305.               (* enter reduce action: *)
  306.               add_redn(lookahead_table^[item_lo+i-1], rule_no);
  307.           (* process nonkernel items: *)
  308.           (* find successor items: *)
  309.           for k := trans_lo to trans_hi do
  310.             with trans_table^[k] do
  311.               for i := n_kernel_items+1 to n_items do
  312.                 with item[i], rule_table^[rule_no]^ do
  313.                   if pos_no>rhs_len then
  314.                     next := 0
  315.                   else if rhs_sym[pos_no]=sym then
  316.                     next := find_item(next_state, rule_no, pos_no+1);
  317.           (* add spontaneous lookaheads and propagation links: *)
  318.           for i := n_kernel_items+1 to n_items do with item[i] do
  319.             if next>0 then
  320.               (* lookaheads are generated spontaneously for successor
  321.                  item: *)
  322.               for j := 1 to size(lookahead_set[i]) do
  323.                 if lookahead_set[i][j]>=0 then
  324.                   include(lookahead_table^[next]^, lookahead_set[i][j])
  325.                 else
  326.                   add_prop(item_lo+(-lookahead_set[i][j])-1,
  327.                            lookahead_table^[next])
  328.             else
  329.               (* nonkernel reduction item: *)
  330.               begin
  331.                 lookaheads := newEmptyIntSet;
  332.                 for j := 1 to size(lookahead_set[i]) do
  333.                   if lookahead_set[i][j]>=0 then
  334.                     include(lookaheads^, lookahead_set[i][j])
  335.                   else
  336.                     add_prop(item_lo+(-lookahead_set[i][j])-1,
  337.                              lookaheads);
  338.                 add_redn(lookaheads, rule_no);
  339.               end;
  340.           end_redns;
  341.           sort_redns;
  342.         end;
  343.       inc(act_state);
  344.     until act_state=n_states;
  345.   end(*initialize*);
  346.  
  347. procedure propagate;
  348.  
  349.   (* propagation phase of lookahead computation algorithm *)
  350.  
  351.   var i, l : Integer;
  352.       done : Boolean;
  353.       prop : PropList;
  354.  
  355.   begin
  356.     (* repeated passes over the kernel items table until no more lookaheads
  357.        could be added in the previous pass: *)
  358.     repeat
  359.       done := true;
  360.       for i := 1 to n_items do
  361.         begin
  362.           prop := prop_table^[i];
  363.           while prop<>nil do with prop^ do
  364.             begin
  365.               l := size(symset^);
  366.               setunion(symset^, lookahead_table^[i]^);
  367.               if size(symset^)>l then done := false;
  368.               prop := next;
  369.             end;
  370.         end;
  371.     until done;
  372.   end(*propagate*);
  373.  
  374. procedure lookaheads;
  375.   begin
  376.     initialize;
  377.     propagate;
  378.   end(*lookaheads*);
  379.  
  380. end(*YaccLookaheads*).
  381.